#include <bits/stdc++.h>
using namespace std;

#define MAX_N 100 // 最多的节点数目

int parent[MAX_N]; // 存储每个节点的父节点的表
int deep[MAX_N];   // 存储每个节点的秩，即路径深度

// 加了秩的优化版本
void initOptimize(int n)
{
    for(int i=0; i<n; i++)
    {
        parent[i] = i;
        deep[i] = 1;
    }
}

// 加入路径压缩算法的优化版
int findOptimize(int ele)
{
    int pos_root = ele;

    while(parent[pos_root] != pos_root)
        pos_root = parent[pos_root];

    // 更新当前节点的根节点路径
    parent[ele] = pos_root;

    return pos_root;
}

// 加入秩的优化版本
bool mergeOptimize(int x, int y)
{
    int x_root = findOptimize(x);
    int y_root = findOptimize(y);

    if(x_root == y_root)
        return false;

    if(deep[x_root] <= deep[y_root])
        parent[x_root] = y_root;
    else
        parent[y_root] = x_root;

    if(deep[x_root] == deep[y_root] && x_root!=y_root)
        deep[y_root]++;

    return true;
}

int main(int argc, char const *argv[])
{
    // 输入给定的一个图
    // n个节点，n条边
    int n, m;
    cin >> n >> m;

    // 初始化并查集
    initOptimize(n);

    // 读入m条边，并逐个将他们合并
    for(int i=0; i<m; i++)
    {
        int x, y;
        cin >> x >> y;

        if(mergeOptimize(x, y) == false)
        {
            cout << "有环！" << endl;
            exit(0);
        }
    }

    cout << "没有环！" << endl;

    return 0;
}
